home *** CD-ROM | disk | FTP | other *** search
- /*
- * powerd Monitor the DCD line of a serial port connected to
- * an UPS. If the power goes down, notify init.
- * If the power comes up again, notify init again.
- * As long as the power is OK, the DCD line should be
- * "HIGH". When the power fails, DCD should go "LOW".
- * Powerd keeps DTR high so that you can connect
- * DCD and DTR with a resistor of 10 Kilo Ohm and let the
- * UPS or some relais pull the DCD line to ground.
- * You also need to connect DTR and DSR together. This
- * way, powerd can check now and then if DSR is high
- * so it knows the UPS is connected!!
- *
- * Usage: powerd /dev/cua4 (or any other serial device).
- *
- * Author: Miquel van Smoorenburg, <miquels@drinkel.cistron.nl>.
- *
- * Version: 1.31, 29-Feb-1996.
- *
- * This program was originally written for my employer,
- * ** Cistron Electronics **
- * who has given kind permission to release this program
- * for general puppose.
- *
- * Copyright 1991-1996 Cistron Electronics.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
- /* Use the new way of communicating with init. */
- #define NEWINIT
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <signal.h>
- #include <syslog.h>
- #include <string.h>
- #include "paths.h"
- #ifdef NEWINIT
- #include "initreq.h"
- #endif
-
- #ifndef SIGPWR
- # define SIGPWR SIGUSR1
- #endif
-
- #ifdef NEWINIT
- void alrm_handler()
- {
- }
- #endif
-
- /* Tell init the power has either gone or is back. */
- void powerfail(ok)
- int ok;
- {
- int fd;
- #ifdef NEWINIT
- struct init_request req;
-
- /* Fill out the request struct. */
- memset(&req, 0, sizeof(req));
- req.magic = INIT_MAGIC;
- req.cmd = ok ? INIT_CMD_POWEROK : INIT_CMD_POWERFAIL;
-
- /* Open the fifo (with timeout) */
- signal(SIGALRM, alrm_handler);
- alarm(3);
- if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0
- && write(fd, &req, sizeof(req)) == sizeof(req)) {
- close(fd);
- return;
- }
- /* Fall through to the old method.. */
- #endif
-
- /* Create an info file for init. */
- unlink(PWRSTAT);
- if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) {
- if (ok)
- write(fd, "OK\n", 3);
- else
- write(fd, "FAIL\n", 5);
- close(fd);
- }
- kill(1, SIGPWR);
- }
-
- /* Main program. */
- int main(int argc, char **argv)
- {
- int fd;
- int dtr_bit = TIOCM_DTR;
- int flags;
- int status, oldstat = -1;
- int count = 0;
- int tries = 0;
-
- if (argc < 2) {
- fprintf(stderr, "Usage: powerd <device>\n");
- exit(1);
- }
-
- /* Start syslog. */
- openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON);
-
- /* Open monitor device. */
- if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
- syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]);
- closelog();
- exit(1);
- }
-
- /* Line is opened, so DTR is high. Force it anyway to be sure. */
- ioctl(fd, TIOCMBIS, &dtr_bit);
-
- /* Daemonize. */
- switch(fork()) {
- case 0: /* Child */
- closelog();
- setsid();
- break;
- case -1: /* Error */
- syslog(LOG_ERR, "can't fork.");
- closelog();
- exit(1);
- default: /* Parent */
- closelog();
- exit(0);
- }
-
- /* Restart syslog. */
- openlog("powerd", LOG_CONS, LOG_DAEMON);
-
- /* Now sample the DCD line. */
- while(1) {
- /* Get the status. */
- ioctl(fd, TIOCMGET, &flags);
-
- /* Check the connection: DSR should be high. */
- tries = 0;
- while((flags & TIOCM_DSR) == 0) {
- /* Keep on trying, and warn every two minutes. */
- if ((tries % 60) == 0)
- syslog(LOG_ALERT, "UPS connection error");
- sleep(2);
- tries++;
- ioctl(fd, TIOCMGET, &flags);
- }
- if (tries > 0)
- syslog(LOG_ALERT, "UPS connection OK");
-
- /* Calculate present status. */
- status = (flags & TIOCM_CAR);
-
- /* Did DCD drop to zero? Then the power has failed. */
- if (oldstat != 0 && status == 0) {
- count++;
- if (count > 3)
- powerfail(0);
- else {
- sleep(1);
- continue;
- }
- }
- /* Did DCD come up again? Then the power is back. */
- if (oldstat == 0 && status > 0) {
- count++;
- if (count > 3)
- powerfail(1);
- else {
- sleep(1);
- continue;
- }
- }
- /* Reset count, remember status and sleep 2 seconds. */
- count = 0;
- oldstat = status;
- sleep(2);
- }
- /* Never happens */
- return(0);
- }
-